// fast4j - Fast & Agile Service Tools for Java
// Copyright (C) 2007 Alexandre ROMAN
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

// $Id: ACE.java 71 2007-04-12 22:22:11Z alexandre.roman $

package fast4j.ace;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Properties;

import org.apache.commons.discovery.resource.ClassLoaders;
import org.apache.commons.discovery.tools.SPInterface;
import org.apache.commons.discovery.tools.Service;
import org.apache.commons.io.FileUtils;

/**
 * Utility methods.
 * @author alexandre.roman
 */
public final class ACE {
    private ACE() {
    }
    
    /**
     * Return registered {@link ApplicationCreator} implementations. This method
     * is expensive, as all classpath resources are checked to find valid
     * implementations.
     * @param classLoader to use
     * @return {@link ApplicationCreator} list, sorted by identifier
     */
    public static List<ApplicationCreator> getApplicationCreators(
            ClassLoader classLoader) {
        final ClassLoaders classLoaders = new ClassLoaders();
        classLoaders.put(classLoader);
        
        @SuppressWarnings("unchecked")
        final List<ApplicationCreator> creators = Collections.list(Service
                .providers(new SPInterface(ApplicationCreator.class),
                    classLoaders));
        Collections.sort(creators, new ApplicationCreatorComparator());
        
        return creators;
    }
    
    /**
     * Create the extension {@link ClassLoader}.
     * @param extensionDirs collection of extension directories
     */
    @SuppressWarnings("unchecked")
    public static ClassLoader createExtensionClassLoader(
            Collection<File> extensionDirs) {
        final ClassLoader classLoader;
        if (!extensionDirs.isEmpty()) {
            final String[] jarExtensions = { "jar" };
            final List<URL> urls = new ArrayList<URL>();
            
            for (final File extensionDir : extensionDirs) {
                // list JAR files
                final Collection<File> jarFiles = (Collection<File>) FileUtils
                        .listFiles(extensionDir, jarExtensions, false);
                try {
                    final List<URL> newUrls = Arrays
                            .asList(FileUtils.toURLs(jarFiles
                                    .toArray(new File[jarFiles.size()])));
                    urls.addAll(newUrls);
                } catch (IOException e) {
                    throw new IllegalStateException(
                            "Failed to add JAR files to ClassLoader from directory: "
                                    + extensionDir.getAbsolutePath(), e);
                }
            }
            
            if (!urls.isEmpty()) {
                // create extension classloader
                classLoader = new URLClassLoader(urls.toArray(new URL[urls
                        .size()]), Thread.currentThread()
                        .getContextClassLoader());
            } else {
                classLoader = Thread.currentThread().getContextClassLoader();
            }
        } else {
            classLoader = Thread.currentThread().getContextClassLoader();
        }
        
        return classLoader;
    }
    
    /**
     * Return registered {@link ApplicationCreator} implementations, using the
     * current context {@link ClassLoader}.
     * @see #getApplicationCreators(ClassLoader)
     */
    public static List<ApplicationCreator> getApplicationCreators() {
        return getApplicationCreators(Thread.currentThread()
                .getContextClassLoader());
    }
    
    /**
     * Get application version. The version is read from the file
     * <code>version.properties</code>, under the key
     * <code>app.version</code>.
     */
    public static String getVersion() {
        // version used if not available
        final String notAvailable = "N/A";
        
        // locate version file
        final InputStream input = ACE.class
                .getResourceAsStream("version.properties");
        if (input == null) {
            return notAvailable;
        }
        
        // load version file
        final Properties props = new Properties();
        try {
            props.load(input);
        } catch (IOException e) {
        }
        
        final String versionKey = "ace.version";
        final String version = props.getProperty(versionKey, notAvailable);
        if (version == null) {
            return notAvailable;
        }
        if (version.startsWith("${") && version.endsWith("}")) {
            // version file was not filtered
            return notAvailable;
        }
        return version;
    }
}
